use axum::{
    extract::{DefaultBodyLimit, Query},
    routing::{get, post},
    Router,
};
use serde::Deserialize;

use crate::{
    error::AppErr,
    server::{
        model::{cbor_ok, Cbor, CborRet, IdReq, TypeIdReq, Verify, Void},
        Download,
    },
    store::firm_file::{self, TbFirmFile},
};

#[derive(Debug, Deserialize)]
struct CreateReq {
    type_id: i64,
    name: String,
    description: String,
    version: String,
    #[serde(with = "serde_bytes")]
    body: Box<[u8]>,
}

async fn on_create(_v: Verify, req: Cbor<CreateReq>) -> CborRet<i64> {
    let id = firm_file::create(
        req.type_id,
        &req.name,
        &req.description,
        &req.version,
        &req.body,
    )
    .await?;
    cbor_ok(id)
}

async fn on_delete(_v: Verify, id: Cbor<i64>) -> Result<Void, AppErr> {
    firm_file::delete(id.0).await?;
    Ok(Void)
}

async fn on_query(req: Query<TypeIdReq>) -> CborRet<Box<[TbFirmFile]>> {
    let items = firm_file::query(req.type_id).await?;
    cbor_ok(items)
}

async fn on_download(req: Query<IdReq>) -> Result<Download, AppErr> {
    let download = firm_file::download(req.id).await?;
    Ok(download)
}

pub fn register() -> Router {
    Router::new()
        .route("/create", post(on_create))
        .layer(DefaultBodyLimit::max(10 * 1024 * 1024))
        .route("/delete", post(on_delete))
        .route("/query", get(on_query))
        .route("/download", get(on_download))
}
